/*!
\copyright  Copyright (c) 2023 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file
\brief      Implementation of the audio source interface for LE Audio Client broadcast audio sources.
*/

#ifdef INCLUDE_LE_AUDIO_BROADCAST_SOURCE
#include "le_audio_client_broadcast_audio_source.h"
#include "le_audio_client_context.h"
#include "audio_sources.h"
#include "audio_sources_audio_interface.h"
#include "bt_device.h"
#include "kymera.h"
#include "kymera_adaptation_audio_protected.h"
#include "ui.h"
#include "volume_types.h"

#include <logging.h>
#include <panic.h>
#include <stdlib.h>

static bool leAudioClientBroadcast_GetAudioConnectParameters(audio_source_t source,
                                                             source_defined_params_t *source_params);
static void leAudioClientBroadcast_FreeAudioConnectParameters(audio_source_t source,
                                                              source_defined_params_t *source_params);
static bool leAudioClientBroadcast_GetAudioDisconnectParameters(audio_source_t source,
                                                                source_defined_params_t *source_params);
static void leAudioClientBroadcast_FreeAudioDisconnectParameters(audio_source_t source,
                                                                 source_defined_params_t *source_params);
static bool leAudioClientBroadcast_IsAudioRouted(audio_source_t source);
static source_status_t leAudioClientBroadcast_SetState(audio_source_t source, source_state_t state);
static device_t leAudioClientBroadcast_GetAudioSourceDevice(audio_source_t source);

static const audio_source_audio_interface_t broadcast_audio_source_interface =
{
    .GetConnectParameters = leAudioClientBroadcast_GetAudioConnectParameters,
    .ReleaseConnectParameters = leAudioClientBroadcast_FreeAudioConnectParameters,
    .GetDisconnectParameters = leAudioClientBroadcast_GetAudioDisconnectParameters,
    .ReleaseDisconnectParameters = leAudioClientBroadcast_FreeAudioDisconnectParameters,
    .IsAudioRouted = leAudioClientBroadcast_IsAudioRouted,
    .IsAudioAvailable = NULL,
    .SetState = leAudioClientBroadcast_SetState,
    .Device = leAudioClientBroadcast_GetAudioSourceDevice
};

static bool leAudioClientBroadcast_ExtractAudioParameters(le_audio_connect_parameters_t *conn_param)
{
    le_audio_client_context_t* client_ctxt = leAudioClient_GetContext();
    le_audio_broadcast_session_data_t *session_data = &client_ctxt->broadcast_session_data;

    DEBUG_LOG_INFO("leAudioClientBroadcast_ExtractAudioParameters");

    conn_param->media.stream_type = KYMERA_LE_STREAM_DUAL_MONO;
    conn_param->media.codec_type = KYMERA_LE_AUDIO_CODEC_LC3;
    conn_param->media.codec_version = 0x00;
    conn_param->media_present = TRUE;
    conn_param->media.start_muted = FALSE;
    conn_param->microphone_present = FALSE;
    conn_param->media.codec_frame_blocks_per_sdu = session_data->audio_config->sub_group_info->lc3BlocksPerSdu;
    conn_param->media.sample_rate = leAudioClientBroadcast_GetSampleRate(session_data->sampling_frequency);
    conn_param->media.frame_length = leAudioClient_GetFrameLength(session_data->octets_per_frame,
                                                                  conn_param->media.stream_type, conn_param->media.codec_type);
    conn_param->media.frame_duration = leAudioClient_GetFrameDuration(FALSE, LE_AUDIO_CLIENT_MODE_BROADCAST, conn_param->media.stream_type);
    conn_param->media.source_iso_handle = session_data->bis_handles[0];
    conn_param->media.source_iso_handle_right = session_data->bis_handles[1];
    conn_param->media.volume = AudioSources_CalculateOutputVolume(audio_source_le_audio_broadcast);
    conn_param->media.presentation_delay = session_data->audio_config->presentation_delay;

    DEBUG_LOG_INFO("leAudioClientBroadcast_ExtractAudioParameters sample rate 0x%x, frame_length :0x%x, Frame duration 0x%x, Frame Blocks Per SDU 0x%x codec_type 0x%x codec_version 0x%x Stream Type 0x%x",
                    conn_param->media.sample_rate,
                    conn_param->media.frame_length,
                    conn_param->media.frame_duration,
                    conn_param->media.codec_frame_blocks_per_sdu,
                    conn_param->media.codec_type,
                    conn_param->media.codec_version,
                    conn_param->media.stream_type);

    return TRUE;
}

/* \brief Get Audio Connect parameters */
static bool leAudioClientBroadcast_GetAudioConnectParameters(audio_source_t source,
                                                             source_defined_params_t *source_params)
{
    DEBUG_LOG_INFO("leAudioClientBroadcast_GetAudioConnectParameters");

    bool populate_success = FALSE;
    le_audio_connect_parameters_t *conn_param = (le_audio_connect_parameters_t*)PanicUnlessMalloc(sizeof(le_audio_connect_parameters_t));
    memset(conn_param, 0, sizeof(le_audio_connect_parameters_t));

    PanicFalse(LeAudioClient_IsBroadcastSourceStreamingActive());

    if (source == audio_source_le_audio_broadcast)
    {
        if (leAudioClientBroadcast_ExtractAudioParameters(conn_param))
        {
            source_params->data = (void *)conn_param;
            source_params->data_length = sizeof(le_audio_connect_parameters_t);
            populate_success = TRUE;
        }
        else
        {
            /* Free the allocated audio connect parameter */
            free(conn_param);
        }
    }
    return populate_success;
}

static void leAudioClientBroadcast_FreeAudioConnectParameters(audio_source_t source,
                                                              source_defined_params_t *source_params)
{
    if (source == audio_source_le_audio_broadcast)
    {
        PanicNull(source_params);
        PanicFalse(source_params->data_length == sizeof(le_audio_connect_parameters_t));

        free(source_params->data);
        source_params->data = (void *) NULL;
        source_params->data_length = 0;
    }
}

static bool leAudioClientBroadcast_GetAudioDisconnectParameters(audio_source_t source,
                                                                source_defined_params_t *source_params)
{
    /* Todo */
    UNUSED(source_params);
    UNUSED(source);
    return TRUE;
}

static void leAudioClientBroadcast_FreeAudioDisconnectParameters(audio_source_t source,
                                                                 source_defined_params_t *source_params)
{
    /* Todo */
    UNUSED(source_params);
    UNUSED(source);
}

static bool leAudioClientBroadcast_IsAudioRouted(audio_source_t source)
{
    /* Todo */
    UNUSED(source);
    return FALSE;
}

static source_status_t leAudioClientBroadcast_SetState(audio_source_t source, source_state_t state)
{
    DEBUG_LOG("leAudioClientBroadcast_SetState source=%d state=%d", source, state);
    /* TODO */
    return source_status_ready;
}

static device_t leAudioClientBroadcast_GetAudioSourceDevice(audio_source_t source)
{
    UNUSED(source);
    return NULL;
}

void leAudioClient_InitBroadcastAudioSource(void)
{
    AudioSources_RegisterAudioInterface(audio_source_le_audio_broadcast, &broadcast_audio_source_interface);
}

#endif /* INCLUDE_LE_AUDIO_BROADCAST_SOURCE */

